/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alexandre-barbosa.com/

 Copyright (c) 2008 Alexandre Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef SYMBOL_ITEM_H
#define SYMBOL_ITEM_H

#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
#include <iostream>
#include <list>
#include <string>

#include "cnome_iterator.h"
#include "cnome_typedefs.h"
#include "tst_avl.h"

namespace cnome {
class symbolItem : public token_t {
public:
	typedef	std::list<symbolItemPtr> innersT;
	typedef	innersT::iterator it_innersT;

	enum symbolType
	{
		unknown,
		internal, // for internal use by grammar engine
		keyword,  // char, int, long, float, double, boolean
		member,
		method,
		enumerator,
		enun_name,
		parameter,
		typedefname,
		point_to_function,
		template_variable,
		other,
		last_symbolType 
	};

	enum identifierType
	{
		NONE,
		T_CLASS_NAME,
		T_ENUM_NAME,
		T_ORIGINAL_NAMESPACE_NAME,
		T_TEMPLATE_NAME,
		T_NAMESPACE_ALIAS,
		T_TYPEDEF_NAME,
		T_TEMPLATE_PARAMETER,
		T_TEMPLATE_VARIABLE
	};

	static const char* strSymbolType[last_symbolType];

	enum statusDD  // Status of Data Declaration/Definition
	{
		unknow,
		declared,
		defined,
		last_statusDD 
	};
	static const char* strStatusDD[last_statusDD];

	// TODO: Review constructors in order to analyze the posibility of ones having the same parameters of token_t
	symbolItem();
	symbolItem(boost::wave::token_id argTkId, std::size_t a_pos);
	symbolItem(const token_t& argTk, symbolType s, std::size_t a_pos);
	symbolItem(const symbolItem& s);
	virtual ~symbolItem();

	void set_token(const token_t& tk)
	{
		*static_cast<token_t*>(this)=tk;
		update_str();
	}
	symbolType get_symbol_type() const { return m_sblTyp; }
	void  set_symbol_type(symbolType s) {
		m_sblTyp=s;
	    update_str();
	}
	statusDD get_symbol_status() const { return m_stt; }
	void  set_symbol_status(statusDD s) { m_stt=s; }
	const symbolItemPtr get_type_symbol() const { return m_typeTk; }
	void  set_type_symbol(const symbolItemPtr s);
	const symbolItemPtr get_scope() const { return m_scope; }
	void  set_scope(const symbolItemPtr s);
	const adornersT& get_adorners() { return m_adorners; }
	void  set_adorners(const adornersT& a) { m_adorners=a; }
	const char* to_str(void) const { return m_str; }
	symbolItem& operator=(const symbolItem&);
	symbolItem& operator*();
	symbolItemPtr  add(symbolItemPtr);
	const symbolItemPtr  add(const symbolItem&);
	innersT& get_inners() { return m_inners; }
	void set_inners(const innersT& inners) { m_inners=inners; }
	int  get_parameter_position() { return m_paramPos; }
	void set_parameter_position(int p) { m_paramPos = p; }
	identifierType get_identifier_type() const { return m_identifierType; }
	void set_identifier_type(identifierType id) { m_identifierType = id; }
	const std::size_t get_cnome_position() { return m_pos; }
	void set_cnome_position(std::size_t a) { m_pos = a; }
	std::set<cnome_iterator>& get_definitions() { return m_definitions; }
	std::set<cnome_iterator>& get_declarations() { return m_declarations; }
	std::map<cnome_iterator, symbolItemPtr>& get_references() { return m_references; }


	/*operator token_t() { return definitions.size() ? definitions.back() : declarations.size() ? declarations.back() : token_t(boost::wave::T_UNKNOWN, "", token_t::position_type()); }
	operator token_t() const { return definitions.size() ? definitions.back() : declarations.size() ? declarations.back() : token_t(boost::wave::T_UNKNOWN, "", token_t::position_type()); }
	
	operator boost::wave::token_id() const { return static_cast<token_t>(*this); }
	token_t::string_type const &get_value() const { return static_cast<token_t>(*this).get_value(); }
	token_t::position_type const &get_position() const { return static_cast<token_t>(*this).get_position(); }
	token_annotation_ptrT const &get_annotation() const { return static_cast<token_t>(*this).get_annotation(); }
    token_annotation_ptrT &get_annotation() { return static_cast<token_t>(*this).get_annotation(); }

    void set_token_id (boost::wave::token_id id_) { static_cast<token_t>(*this).set_token_id(id_); }
    void set_value (token_t::string_type const &value_) { static_cast<token_t>(*this).set_value(value_); }
    void set_position (token_t::position_type const &pos_) { static_cast<token_t>(*this).set_position(pos_); }
	void set_annotation (token_annotation_ptrT annotation_) { static_cast<token_t>(*this).set_annotation(annotation_); }*/

protected:
	virtual void update_str(); 

private:
	std::set<cnome_iterator> m_definitions;  // It is valid only one definition
    std::set<cnome_iterator> m_declarations;
	std::map<cnome_iterator, symbolItemPtr> m_references;
    symbolType m_sblTyp;
	symbolItemPtr m_typeTk;    // Pointer to type token if any
	symbolItemPtr m_scope;     // Pointer to enclosing scope if any
	statusDD   m_stt;
	char*      m_str;                   // Contains the entire scope of symbol
	adornersT  m_adorners;
	innersT    m_inners;               // Used by typedef, class methods and fields and method parameters
	innersT    m_inrsCreated;          // Symbols created internally that must be deleted in destructor
	int        m_paramPos;               // Position of parameter in the parameter list.
	identifierType m_identifierType;
	std::size_t m_pos;
};

class mmbORprmItem: public symbolItem  // Member or parameter item
{
	mmbORprmItem(): symbolItem() {}
	mmbORprmItem(boost::wave::token_id argTkId, std::size_t a_pos): symbolItem(argTkId, a_pos) {}
	mmbORprmItem(const token_t& argTk, symbolType s=other, std::size_t a_pos = 0) : symbolItem(argTk, s, a_pos) {}
	bool getHasDefault() { return hasDefault; }
	void setHasDefault(bool d) { hasDefault=d; }
private:
	bool hasDefault;
	symbolItem defaultValue;
};

class classItem: public symbolItem
{
	classItem(): symbolItem() {}
	classItem(boost::wave::token_id argTkId, std::size_t a_pos): symbolItem(argTkId, a_pos) {}
	classItem(const token_t& argTk, symbolType s=other, std::size_t a_pos=0) : symbolItem(argTk, s, a_pos) {}
private:
	std::list<mmbORprmItem*> members;
	// Members bellow is used by type symbol
	bool       isRef;                   
	bool       isPtr;
	bool       isConst;
};

class methodItem: public symbolItem
{
	methodItem(): symbolItem() {}
	methodItem(boost::wave::token_id argTkId, std::size_t a_pos): symbolItem(argTkId, a_pos) {}
	methodItem(const token_t& argTk, symbolType s=other, std::size_t a_pos=0) : symbolItem(argTk, s, a_pos) {}
private:
	std::list<mmbORprmItem*> parameters;
};

const long UNKNOWNANNOTATION     = 0;
const long IDENTIFIERANNOTATION  = 1;
const long PARAMETERANNOTATION   = 2;
const long PARENTHESISANNOTATION = 3;

class identifier_annotation : public token_annotation
{
public:
	identifier_annotation(symbolItemPtr const &symbol_item_ptr_, symbolItem::identifierType id_type_) 
		: symbol_item_ptr(symbol_item_ptr_), id_type(id_type_) {}
	virtual tag_type get_tag() const { return IDENTIFIERANNOTATION; }

	symbolItemPtr& get_symbol_item_ptr() { return symbol_item_ptr; }
	void set_symbol_item_ptr(symbolItemPtr const& symbol_item_ptr_)
	{ symbol_item_ptr = symbol_item_ptr_; }
	symbolItem::identifierType get_id_type() { return id_type; }
	void set_id_type(symbolItem::identifierType id_type_) { id_type = id_type_; }

private:
    symbolItemPtr symbol_item_ptr;
	symbolItem::identifierType id_type;
};

class parameter_annotation : public identifier_annotation
{
public:
	parameter_annotation(symbolItemPtr const &symbol_item_ptr_, symbolItem::identifierType id_type_,
		int level_, const std::string& index_, eParameterType parameter_type_ = method_parameter): 
	    identifier_annotation(symbol_item_ptr_, id_type_), 
		level(level_), index(index_), parameter_type(parameter_type_) {}
	virtual tag_type get_tag() const { return PARAMETERANNOTATION; }

	int get_level() const { return level; }
	void set_level(int level_) { level = level_; }
	const std::string& get_index() const { return index; }
	void set_index(const std::string& index_) { index = index_; }
	eParameterType get_parameter_type() { return parameter_type; }
	void set_parameter_type(eParameterType parameter_type_) { parameter_type = parameter_type_; }
private:
	int level;
	std::string index;
	eParameterType parameter_type;

};

class parenthesis_annotation : public token_annotation {
public:
	enum eparenthesis_type {
		unknown_type,
		method_type,
		ptr_to_fct_type
	};

	parenthesis_annotation(int level_, eparenthesis_type parenthesis_type_) : level(level_), parenthesis_type(parenthesis_type_) {}
	virtual tag_type get_tag() const { return PARENTHESISANNOTATION; }

	int get_level() const { return level; }
	void set_level(int level_) { level = level_; }

	eparenthesis_type get_parenthesis_type() { return parenthesis_type; }
	void set_parenthesis_type(eparenthesis_type parenthesis_type_) { parenthesis_type = parenthesis_type_; }
private:
	int level;
	eparenthesis_type parenthesis_type;
};

extern cnome::tst_avl::tst_avl<std::string, symbolItemPtr> cnome_symbols;
extern symbolItem const smb_FIRST_TOKEN;
}  // namespace cnome

#endif // SYMBOL_ITEM_H
